#include "sceneMain.h"
#include "../manager/gameMer.h"
#include <stdio.h>
#include "SDL.h"
#include <random>
#include "sceneTitle.h"
#include "sceneEnd.h"

STG::sceneMain::sceneMain()
{
}

STG::sceneMain::~sceneMain()
{
}

void STG::sceneMain::init(){

    std::random_device rd;
    gen = std::mt19937(rd()); //随机数生成器
    dis = std::uniform_real_distribution<float>(0.0f, 1.0f);

    //初始化玩家
    player.texture = IMG_LoadTexture(GameMer::instance()->getRenderer(),"../assets/image/SpaceShip.png");
    if( player.texture == NULL){
        printf("Failed to load texture image!\n");
    }
    SDL_QueryTexture(player.texture,NULL,NULL,&player.width,&player.height);
    player.width /= 5;
    player.height /= 5;
    player.position.x = (float)GameMer::instance()->getWidth()/2 - (float)player.width/2;
    player.position.y = (float)GameMer::instance()->getHeight() - (float)player.height;

    //初始化玩家子弹
    bulletPtemp.texture = IMG_LoadTexture(GameMer::instance()->getRenderer(),"../assets/image/bullet.png");
    SDL_QueryTexture(bulletPtemp.texture,NULL,NULL,&bulletPtemp.width,&bulletPtemp.height);
    bulletPtemp.width /= 4;
    bulletPtemp.height /= 4;

    //初始化敌人
    EnemyTemp.texture = IMG_LoadTexture(GameMer::instance()->getRenderer(),"../assets/image/insect-2.png");
    SDL_QueryTexture(EnemyTemp.texture,NULL,NULL,&EnemyTemp.width,&EnemyTemp.height);
    EnemyTemp.width /= 4;
    EnemyTemp.height /= 4;

    //初始化子弹容器
    bulletEtemp.texture = IMG_LoadTexture(GameMer::instance()->getRenderer(),"../assets/image/bullet-1.png");
    SDL_QueryTexture(bulletEtemp.texture,NULL,NULL,&bulletEtemp.width,&bulletEtemp.height);
    bulletEtemp.width /= 2;
    bulletEtemp.height /= 2;

    //初始化爆炸特效
    explosionTemp.texture = IMG_LoadTexture(GameMer::instance()->getRenderer(),"../assets/effect/explosion.png");
    SDL_QueryTexture(explosionTemp.texture,NULL,NULL,&explosionTemp.width,&explosionTemp.height);
    explosionTemp.totlaFrame = explosionTemp.width / explosionTemp.height;
    explosionTemp.height *= explosionTemp.scale;
    explosionTemp.width = explosionTemp.height;

    //初始化道具
    itemTemp.texture = IMG_LoadTexture(GameMer::instance()->getRenderer(),"../assets/image/bonus_life.png");
    SDL_QueryTexture(itemTemp.texture,NULL,NULL,&itemTemp.width,&itemTemp.height);
    if(itemTemp.texture == NULL){
        printf("Failed to load texture image!\n");
    }
    itemTemp.width /= 4;
    itemTemp.height /= 4;

    //初始化生命值UI
    UiLife = IMG_LoadTexture(GameMer::instance()->getRenderer(),"../assets/image/Health UI Black.png");

    GameMer::instance()->setScore(0);

    bgm = Mix_LoadMUS("../assets/music/03_Racing_Through_Asteroids_Loop.ogg");
    if(bgm == nullptr){
        SDL_LogError(SDL_LOG_CATEGORY_ERROR,"Mix_LoadMUS Error: %s\n", Mix_GetError());
        return;
    }else{
        Mix_PlayMusic(bgm, -1);
    }

}

void STG::sceneMain::update(float deltaTime){
    //printf("main update\n");
    //SDL_Log("main update dt: %f\n",deltaTime);
    keyPressed(deltaTime);
    updateBullet(deltaTime);
    updateEnemyBullet(deltaTime);
    spawnEnemy();
    updateEnemy(deltaTime);
    updatePlayer(deltaTime);
    updateExplosion(deltaTime);
    updateItem(deltaTime);
    if(player.isDead){
        scene* scene = new sceneEnd();
        changeSceneDelayed(deltaTime,3, scene);
    }
}
void STG::sceneMain::clean(){
    //清理子弹容器
    for(auto &bullet : bulletPList){
        if(bullet->texture != nullptr){
            SDL_DestroyTexture(bullet->texture);
            bullet->texture = nullptr;
        }
    }
    bulletPList.clear();

    //清理敌人容器
    for(auto &enemy : enemyList){
        if(enemy->texture != nullptr){
            SDL_DestroyTexture(enemy->texture);
            enemy->texture = nullptr;
        }
    }
    enemyList.clear();

    //清理敌人子弹容器
    for(auto &bullet : bulletEList){
        if(bullet->texture != nullptr){
            SDL_DestroyTexture(bullet->texture);
            bullet->texture = nullptr;
        }
    }
    bulletEList.clear();

    //清理爆炸特效容器
    for(auto &explosion : explosionList){
        if(explosion->texture != nullptr){
            SDL_DestroyTexture(explosion->texture);
            explosion->texture = nullptr;
        }
    }
    explosionList.clear();


    //清理道具容器
    for(auto &item : itemList){
        if(item->texture != nullptr){
            SDL_DestroyTexture(item->texture);
            item->texture = nullptr;
        }   
    }
    itemList.clear();

    //清理纹理
    if(bulletPtemp.texture != nullptr){
        SDL_DestroyTexture(bulletPtemp.texture);
        bulletPtemp.texture = nullptr;
    }
    if(EnemyTemp.texture != nullptr){
        SDL_DestroyTexture(EnemyTemp.texture);
        EnemyTemp.texture = nullptr;
    }
    if(player.texture != nullptr){
        SDL_DestroyTexture(player.texture);
        player.texture = nullptr;
    }
    if(bulletEtemp.texture != nullptr){
        SDL_DestroyTexture(bulletEtemp.texture);
        bulletEtemp.texture = nullptr;
    }
    if(explosionTemp.texture != nullptr){
        SDL_DestroyTexture(explosionTemp.texture);
        explosionTemp.texture = nullptr;    
    }
    if(itemTemp.texture != nullptr){
        SDL_DestroyTexture(itemTemp.texture);
        itemTemp.texture = nullptr; 
    }
    if(UiLife != nullptr){
        SDL_DestroyTexture(UiLife);
        UiLife = nullptr;
    }
    if(bgm != nullptr){
        Mix_HaltMusic();
        Mix_FreeMusic(bgm);
    }
}
void STG::sceneMain::render(){
    renderBullet();
    renderEnemyBullet();
    renderEnemy();
    //printf("player position x: %f y: %f,player width: %d height: %d\n",player.position.x,player.position.y, player.width,player.height);
    if(!player.isDead){
        SDL_Rect src = { static_cast<int>(player.position.x),static_cast<int>(player.position.y),player.width,player.height};
        SDL_RenderCopy(GameMer::instance()->getRenderer(),player.texture,NULL,&src);
    }
    renderItem();
    renderExplosion();
    renderUI();
}

void STG::sceneMain::handleEvents(SDL_Event *event){
    if(event->type == SDL_KEYDOWN){
        if(event->key.keysym.sym == SDLK_ESCAPE){
        scene* scene = new sceneTitle();
        GameMer::instance()->changeScene(scene);
        }
    }
}

int STG::sceneMain::keyPressed(float deltaTime)
{
    if(player.isDead)
        return 0;
    auto key = SDL_GetKeyboardState(NULL);
    //printf("up%d down%d left%d right%d\n",key[SDL_SCANCODE_UP],key[SDL_SCANCODE_DOWN],key[SDL_SCANCODE_LEFT],key[SDL_SCANCODE_RIGHT]);
    /*for(int i = 0; i < 256; i++){
        if(key[i]){
            printf("key %d is pressed\n",i);
        }
    }*/
    if(key[SDL_SCANCODE_UP] | key[SDL_SCANCODE_W]){
        player.position.y -= deltaTime * player.speed;
        //printf("player position W");
    }
    if(key[SDL_SCANCODE_DOWN] | key[SDL_SCANCODE_S]){
        player.position.y += deltaTime * player.speed;
        //printf("player position S");
    }
    if(key[SDL_SCANCODE_LEFT] | key[SDL_SCANCODE_A]){
        player.position.x -= deltaTime * player.speed; 
        //printf("player position A");
    }
    if(key[SDL_SCANCODE_RIGHT] | key[SDL_SCANCODE_D]){
        player.position.x += deltaTime * player.speed;
        //printf("player position D");
    }

    if(player.position.x < 0){
        player.position.x = 0;
    }
    if(player.position.x > GameMer::instance()->getWidth() - player.width){
        player.position.x = static_cast<float>(GameMer::instance()->getWidth() - player.width);
    }
    if(player.position.y < 0){
        player.position.y = 0;
    }
    if(player.position.y > GameMer::instance()->getHeight() - player.height){
        player.position.y = static_cast<float>(GameMer::instance()->getHeight() - player.height);
    }

    if(key[SDL_SCANCODE_J]){
        auto currentTime = SDL_GetTicks();
        if(currentTime - player.lastShotTime > player.coolDown){
            player.lastShotTime = currentTime;
            playerShoot();
        }
    }
    return 0;
}

int STG::sceneMain::playerShoot(){
    auto bullet = new STG::bulletPlayer(bulletPtemp);
    bullet->position.x = player.position.x + player.width/2 - bullet->width/2;
    bullet->position.y = player.position.y;
    bulletPList.push_back(bullet);
    Mix_PlayChannel(0,GameMer::instance()->getSoundEffect()["player_shoot"],0);
    //printf("player shot\n");
    return 0;
}

void STG::sceneMain::updateBullet(float deltaTime)
{
    for(auto it = bulletPList.begin(); it != bulletPList.end();){
        (*it)->position.y -= deltaTime * (*it)->speed;
        if((*it)->position.y < 0){
            delete *it;
            it = bulletPList.erase(it);
        }else{
            bool hit = false;
            for (auto enemy : enemyList)
            {
                SDL_Rect enemyRect = { static_cast<int>(enemy->position.x),static_cast<int>(enemy->position.y),enemy->width,enemy->height};
                SDL_Rect bulletRRect = { static_cast<int>((*it)->position.x),static_cast<int>((*it)->position.y),(*it)->width,(*it)->height};
                if(SDL_HasIntersection(&enemyRect,&bulletRRect)){
                    enemy->hp -= (*it)->damage;
                    delete *it;
                    it = bulletPList.erase(it);
                    hit = true;
                    Mix_PlayChannel(-1,GameMer::instance()->getSoundEffect()["hit"],0);
                    break;
                }
            }
            if(!hit)
                it++;
        }
    }
}

void STG::sceneMain::renderBullet()
{
    for(auto bullet : bulletPList){
        SDL_Rect src = { static_cast<int>(bullet->position.x),static_cast<int>(bullet->position.y),bullet->width,bullet->height};
        SDL_RenderCopy(GameMer::instance()->getRenderer(),bullet->texture,NULL,&src);
    }
}

void STG::sceneMain::spawnEnemy()
{
    if(dis(gen) > 1 / 60.0f /*|| player.isDead*/)
        return;
    Enemy* enemy = new Enemy(EnemyTemp);
    enemy->position.x = dis(gen) * (GameMer::instance()->getWidth() - enemy->width);
    enemy->position.y = static_cast<float>(-enemy->height);
    enemyList.push_back(enemy);
}

void STG::sceneMain::updateEnemy(float deltaTime)
{
    auto currentTime = SDL_GetTicks();
    for(auto it = enemyList.begin(); it != enemyList.end();){
        (*it)->position.y += deltaTime * (*it)->speed;
        if((*it)->position.y > GameMer::instance()->getHeight()){
            delete *it;
            it = enemyList.erase(it);
        }else{
            if(currentTime - (*it)->lastShotTime > (*it)->coolDown && !player.isDead){ 
                (*it)->lastShotTime = currentTime;
                enemyShoot(*it);
            }
            if((*it)->hp <= 0){
                GameMer::instance()->addScore(10);
                enemyExplode(*it);
                it = enemyList.erase(it);
            }else{
                it++;
            }
        }
    }
}

void STG::sceneMain::changeSceneDelayed(float deltaTime, float delayTime, scene * scene)
{
    timeEnd += deltaTime;
    //SDL_Log("timeEnd: %f, delayTime: %f",timeEnd,delayTime);
    if(timeEnd > delayTime){
        GameMer::instance()->changeScene(scene);
        timeEnd = 0;
    }
}

void STG::sceneMain::renderEnemy()
{
    for(auto enemy : enemyList){
        SDL_Rect src = { static_cast<int>(enemy->position.x),static_cast<int>(enemy->position.y),enemy->width,enemy->height};
        SDL_RenderCopy(GameMer::instance()->getRenderer(),enemy->texture,NULL,&src);    
    }
}

void STG::sceneMain::enemyShoot(Enemy *enemy)
{
    auto bullet = new STG::bulletEnemy(bulletEtemp);
    bullet->position.x = enemy->position.x + enemy->width/2 - bullet->width/2;
    bullet->position.y = enemy->position.y + enemy->height/2 - bullet->height/2;
    bullet->direction = getDirection(enemy);
    bulletEList.push_back(bullet);
    Mix_PlayChannel(-1,GameMer::instance()->getSoundEffect()["enemy_shoot"],0);
    //printf("enemy shot\n");
}

void STG::sceneMain::updateEnemyBullet(float deltaTime)
{
    for(auto it = bulletEList.begin(); it != bulletEList.end();){
        (*it)->position.x += deltaTime * (*it)->direction.x * (*it)->speed;
        (*it)->position.y += deltaTime * (*it)->direction.y * (*it)->speed;
        if((*it)->position.x < 0 || (*it)->position.x > GameMer::instance()->getWidth() - (*it)->width || (*it)->position.y > GameMer::instance()->getHeight()){
            delete *it;
            it = bulletEList.erase(it);
        }else{
            SDL_Rect playerRect = { static_cast<int>(player.position.x),static_cast<int>(player.position.y),player.width,player.height};
            SDL_Rect bulletERect = { static_cast<int>((*it)->position.x),static_cast<int>((*it)->position.y),(*it)->width,(*it)->height};
            if(SDL_HasIntersection(&playerRect,&bulletERect) && !player.isDead){
                player.hp -= (*it)->damage;
                delete *it;
                it = bulletEList.erase(it);
                Mix_PlayChannel(-1,GameMer::instance()->getSoundEffect()["hit"],0);
            }
            else{
                it++;
            }
        }
    }
}

void STG::sceneMain::renderEnemyBullet()
{
    for(auto bullet : bulletEList){
        SDL_Rect src = { static_cast<int>(bullet->position.x),static_cast<int>(bullet->position.y),bullet->width,bullet->height};
        //SDL_RenderCopy(GameMer::instance()->getRenderer(),bullet->texture,NULL,&src);
        float angle = static_cast<float>(atan2(bullet->direction.y, bullet->direction.x) * 180 / M_PI - 90);
        SDL_RenderCopyEx(GameMer::instance()->getRenderer(),bullet->texture,NULL,&src,angle,NULL,SDL_FLIP_NONE);
    }
}

SDL_FPoint STG::sceneMain::getDirection(Enemy *enemy)
{
    auto x = (player.position.x + player.width/2) - (enemy->position.x + enemy->width/2);
    auto y = (player.position.y + player.height/2) - (enemy->position.y + enemy->height/2);
    auto length = sqrt(x*x + y*y);
    x /= length;
    y /= length;
    return SDL_FPoint{x,y};
}

void STG::sceneMain::enemyExplode(Enemy *enemy)
{
    auto explosion = new STG::explosion(explosionTemp);
    explosion->position.x = enemy->position.x + enemy->width/2 - explosion->width/2;
    explosion->position.y = enemy->position.y + enemy->height/2 - explosion->height/2;
    auto explosionTime = SDL_GetTicks();
    explosion->startTime = explosionTime;
    explosionList.push_back(explosion);
    Mix_PlayChannel(-1,GameMer::instance()->getSoundEffect()["enemy_explode"],0);
    if(dis(gen) < 0.5f){
        dropItem(enemy);
    }
    delete enemy;
}

void STG::sceneMain::updatePlayer(float)
{
    if(player.isDead)
    {
        return;
    }
    if(player.hp <= 0){
        //TODO: Game Over
        player.isDead = true;
        auto explosion = new STG::explosion(explosionTemp);
        explosion->position.x = player.position.x + player.width/2 - explosion->width/2;
        explosion->position.y = player.position.y + player.height/2 - explosion->height/2;
        auto explosionTime = SDL_GetTicks();
        explosion->startTime = explosionTime;
        explosionList.push_back(explosion);
        Mix_PlayChannel(-1,GameMer::instance()->getSoundEffect()["player_explode"],0);
        return;
    }
}


void STG::sceneMain::updateExplosion(float)
{
    auto currentTime = SDL_GetTicks();
    for(auto it = explosionList.begin(); it != explosionList.end();){
        auto explosion = *it;
        explosion->currentTime = (currentTime - explosion->startTime) * explosion->FPS / 1000;
        if(explosion->currentTime >= explosion->totlaFrame){
            delete explosion;
            it = explosionList.erase(it);
        }else{
            it++;
        }
    }
}

void STG::sceneMain::renderExplosion()
{
    for(auto explosion : explosionList){
        SDL_Rect src = { static_cast<int>(explosion->currentTime * explosion->width),0,explosion->width / explosion->scale,explosion->height / explosion->scale};
        SDL_Rect dst = { static_cast<int>(explosion->position.x),static_cast<int>(explosion->position.y),explosion->width,explosion->height};
        SDL_RenderCopy(GameMer::instance()->getRenderer(),explosion->texture,&src,&dst);
    } 
}

void STG::sceneMain::dropItem(Enemy * enemy)
{
    auto item = new STG::item(itemTemp);
    item->position.x = enemy->position.x + enemy->width/2 - item->width/2;
    item->position.y = enemy->position.y + enemy->height/2 - item->height/2;
    float angle = static_cast<float>(dis(gen) * 2 * M_PI);
    item->direction.x = cos(angle);
    item->direction.y = sin(angle);
    printf("drop item\n");
    itemList.push_back(item);
}

void STG::sceneMain::updateItem(float deltaTime)
{
    for(auto it = itemList.begin(); it != itemList.end();){
        auto item = *it;
        item->position.x += item->direction.x * item->speed * deltaTime;
        item->position.y += item->direction.y * item->speed * deltaTime;
        //处理边缘反弹
        if(item->position.x <0 && item->bounce > 0){
            item->direction.x = -item->direction.x;
            item->bounce--;
        }
        if(item->position.y <0 && item->bounce > 0){
            item->direction.y = -item->direction.y;
            item->bounce--;
        }
        if(item->position.x + item->width > GameMer::instance()->getWidth() && item->bounce > 0)
        {
            item->direction.x = -item->direction.x;
            item->bounce--;
        }
        if(item->position.y + item->height > GameMer::instance()->getHeight() && item->bounce > 0)
        {
            item->direction.y = -item->direction.y;
            item->bounce--; 
        }

        if(item->position.x  + item->width < 0 
            || item->position.x > GameMer::instance()->getWidth() 
        || item->position.y + item->height< 0 
        || item->position.y > GameMer::instance()->getHeight() ){
            delete item;
            it = itemList.erase(it);
        }else{
            SDL_Rect src = { static_cast<int>(player.position.x),static_cast<int>(player.position.y),player.width,player.height};
            SDL_Rect dst = { static_cast<int>(item->position.x),static_cast<int>(item->position.y),item->width,item->height};
            if(SDL_HasIntersection(&src,&dst) && !player.isDead){
                playerGetItem(item);
                GameMer::instance()->addScore(100);
                Mix_PlayChannel(-1,GameMer::instance()->getSoundEffect()["get_item"],0);
                delete item;
                it = itemList.erase(it);
            }else{
                it++;
            }
        }
    }
}

void STG::sceneMain::playerGetItem(item * item)
{
    if(item->type == itemType::life && player.hp < 3){
        player.hp++;
    }
}

void STG::sceneMain::renderItem()
{
    for(auto item : itemList){
        //SDL_Rect src = { static_cast<int>(item->position.x),static_cast<int>(item->position.y),item->width,item->height};
        SDL_Rect dst = { static_cast<int>(item->position.x),static_cast<int>(item->position.y),item->width,item->height};
        SDL_RenderCopy(GameMer::instance()->getRenderer(),item->texture,nullptr,&dst); 
    }
}

// 渲染UI函数
void STG::sceneMain::renderUI()
{
    // TODO: 实现渲染UI的逻辑
    // 例如，渲染玩家血量、得分等UI元素
    int x = 10 , y = 10 , size = 20 , offset = 40;
    SDL_SetTextureColorMod(UiLife,100,100,100);//颜色减淡
    for(int i = 0; i < 3; i++){
        SDL_Rect dst = { x + i * offset , y , size , size };
        SDL_RenderCopy(GameMer::instance()->getRenderer(),UiLife,nullptr,&dst);
    }
    SDL_SetTextureColorMod(UiLife,255,255,255);
    for(int i = 0; i < player.hp; i++){
        SDL_Rect dst = { x + i * offset , y , size , size };
        SDL_RenderCopy(GameMer::instance()->getRenderer(),UiLife,nullptr,&dst);
    }
    std::string text = "Score:" + std::to_string(GameMer::instance()->getScore());
    SDL_Color color = {255,255,255,255};
    SDL_Surface* surface = TTF_RenderUTF8_Solid(GameMer::instance()->getFont(),text.c_str(),color);
    SDL_Texture * texture = SDL_CreateTextureFromSurface(GameMer::instance()->getRenderer(),surface);
    SDL_Rect dst = { GameMer::instance()->getWidth() - surface->w - 10  , y , surface->w , surface->h };
    SDL_RenderCopy(GameMer::instance()->getRenderer(),texture,nullptr,&dst);
    SDL_FreeSurface(surface);
    SDL_DestroyTexture(texture);
}
